package ro.ubbcluj.cs.damate.webutils.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.context.SecurityContextHolder;

import javax.faces.FactoryFinder;
import javax.faces.context.ExternalContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import static ro.ubbcluj.cs.damate.webutils.JSFUtil.*;

public class RedirectToLoginWhenSessionExpiresPhaseListener implements PhaseListener {
    private static Log log = LogFactory.getLog(RedirectToLoginWhenSessionExpiresPhaseListener.class);
    
    @Override
    public void afterPhase(PhaseEvent event) {
        if (isAjaxRequest() && ! isUserLoggedIn()) {
            sendRedirectToLogin();
        }
    }

    @Override
    public void beforePhase(PhaseEvent event) {
    }

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }

    private boolean isAjaxRequest() {
        return facesContext().getPartialViewContext().isAjaxRequest();
    }

    private boolean isUserLoggedIn() {
        return SecurityContextHolder.getContext() != null &&
               SecurityContextHolder.getContext().getAuthentication() != null &&
               SecurityContextHolder.getContext().getAuthentication().isAuthenticated() /*&&
               SecurityContextHolder.getContext().getAuthentication() instanceof PoiAuthentication*/;
    }

    private void sendRedirectToLogin() {
        doRedirect("/login.xhtml?faces-redirect=true&sessionExpired=true");
    }

    /**
     * Does a regular or ajax redirect.
     */
    private void doRedirect(String redirectPage) {
        ExternalContext externalContext = facesContext().getExternalContext();

        try {
            if (externalContext.isResponseCommitted()) {
                // redirect is not possible
                return;
            }

            // fix for renderer kit (Mojarra's and PrimeFaces's ajax redirect)
            ServletResponse response = (ServletResponse) externalContext.getResponse();
            ServletRequest request = (ServletRequest) externalContext.getRequest();
            response.setCharacterEncoding(request.getCharacterEncoding());

            RenderKitFactory factory = (RenderKitFactory)
                    FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);

            RenderKit renderKit = factory.getRenderKit(facesContext(),
                    facesContext().getApplication().getViewHandler().calculateRenderKitId(facesContext()));

            ResponseWriter responseWriter =
                    renderKit.createResponseWriter(
                            response.getWriter(), null, request.getCharacterEncoding());
            facesContext().setResponseWriter(responseWriter);

            log.info("Redirect to " + redirectPage + " due to user not logged in.");
            externalContext.redirect(externalContext.getRequestContextPath() +
                    (redirectPage != null ? redirectPage : ""));
        } catch (Exception e) {
            log.error("Unable to redirect to " + redirectPage, e);
        }
    }
}
